package com.cqfae.deploycentral.app.services.impl;

import com.cqfae.deploycentral.api.utils.IdGenerator;
import com.cqfae.deploycentral.app.base.BaseConstantCode;
import com.cqfae.deploycentral.app.base.BaseConstants;
import com.cqfae.deploycentral.app.config.DeployInfo;
import com.cqfae.deploycentral.app.config.FilePathInfo;
import com.cqfae.deploycentral.app.dao.entity.*;
import com.cqfae.deploycentral.app.dao.mapper.*;
import com.cqfae.deploycentral.app.services.*;
import com.cqfae.deploycentral.app.utils.ConvertUtil;
import com.cqfae.deploycentral.app.utils.GsonUtils;
import com.cqfae.deploycentral.app.utils.NullUtil;
import com.cqfae.deploycentral.app.web.enums.DeployPercentEnum;
import com.cqfae.deploycentral.app.web.enums.LimitStatusEnum;
import com.cqfae.deploycentral.app.web.enums.ProgressColorEnum;
import com.cqfae.deploycentral.app.web.request.DeployActionRequest;
import com.cqfae.deploycentral.app.web.request.WindowPlansRequest;
import com.cqfae.deploycentral.app.web.response.IPage;
import com.cqfae.deploycentral.app.web.vo.WindowPlansFilesVo;
import com.cqfae.deploycentral.app.web.vo.WindowPlansTagVo;
import com.cqfae.deploycentral.app.web.vo.WindowPlansVo;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.google.gson.reflect.TypeToken;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.web.multipart.MultipartFile;
import tk.mybatis.mapper.entity.Example;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import static com.cqfae.deploycentral.app.base.BaseConstantCode.APPROVE_STATUS_SUCCESS_CODE;

/**
 * Created by YANGHENG940 on 2017/7/12.
 */
@Service
@Transactional
public class WindowPlansServiceImpl implements WindowPlansService {

    private static Logger logger = LoggerFactory.getLogger(WindowPlansServiceImpl.class);

    @Autowired
    private IdGenerator idGenerator;

    @Autowired
    private WindowPlansMapper windowPlansMapper;

    @Autowired
    private WindowPlansFilesMapper windowPlansFilesMapper;

    @Autowired
    private WindowInfoMapper windowInfoMapper;

    @Autowired
    private FilePathInfo filePathInfo;

    private String uploadDir = "/uploadFiles/";

    @Autowired
    private ReportInfoMapper reportInfoMapper;

    @Autowired
    private ConvertUtil convertUtil;

    @Autowired
    private WindowPlansTagMapper windowPlansTagMapper;

    @Autowired
    private ReportInfoService reportInfoService;

    @Autowired
    private RemoteService remoteService;

    @Autowired
    private ApproveDocumentMapper approveDocumentMapper;

    @Autowired
    private ApproveAttachmentMapper approveAttachmentMapper;

    @Autowired
    private ExpectPublishEnqueueService expectPublishEnqueueService;

    private int sqlCheckParentCode = 11;

    private int envCheckParentCode = 12;

    @Autowired
    private DeployInfo deployInfo;


    @Autowired
    private JenkinsServiceImpl jenkinsService;

    @Autowired
    private JiraService jiraService;

    @Autowired
    private ReportJiraMapper reportJiraMapper;

    private static final String REPORTCODE = "reportCode";

    @Override
    public IPage<WindowPlansVo> page(WindowPlansRequest request) {
        Page<WindowPlans> page = PageHelper.startPage(request.getPageNum(), request.getPageSize());
        Example example = new Example(WindowPlans.class);
        example.setOrderByClause("window_date DESC");
        Example.Criteria criteria = example.createCriteria();
        if (request.getWindowDate() > 0) {
            criteria.andEqualTo("windowDate", request.getWindowDate());
        }
        if (request.getDeployStatus() > 0) {
            criteria.andEqualTo("deployStatus", request.getDeployStatus());
        }
        if (request.getBeginDate() > 0 || request.getEndDate() > 0) {
            Assert.isTrue(request.getBeginDate() > 0 && request.getEndDate() > 0, "日期不合法，必须有开始和结束日期");
            criteria.andBetween("windowDate", request.getBeginDate(), request.getEndDate());
        }
        if (StringUtils.isNotBlank(request.getReportCode())) {
            criteria.andEqualTo(REPORTCODE, request.getReportCode());
        }
        windowPlansMapper.selectByExample(example);
        IPage<WindowPlansVo> ipage = ConvertUtil.pageToIpage(page, new IPage<WindowPlansVo>());
        List<WindowPlansVo> result = GsonUtils.getInstance().fromJson(GsonUtils.getInstance().toJson(page), new TypeToken<List<WindowPlansVo>>() {
        }.getType());
        for (WindowPlansVo vo : result) {
            WindowPlansFiles windowPlansFiles = new WindowPlansFiles();
            windowPlansFiles.setWindowPlansId(vo.getId());
            windowPlansFiles.setWindowDate(vo.getWindowDate());
            List<WindowPlansFiles> files = windowPlansFilesMapper.select(windowPlansFiles);
            List<WindowPlansFilesVo> filesVos = GsonUtils.getInstance().fromJson(GsonUtils.getInstance().toJson(files), new TypeToken<List<WindowPlansFilesVo>>() {
            }.getType());
            for (WindowPlansFilesVo fileVo : filesVos) {
                fileVo.setFileId(fileVo.getId());
            }
            vo.setFileList(filesVos);

            ReportInfo reportInfo = new ReportInfo();
            reportInfo.setReportCode(vo.getReportCode());
            reportInfo = reportInfoMapper.selectOne(reportInfo);
            if (NullUtil.isNotEmpty(reportInfo)) {
                vo.setReportCodeName(reportInfo.getTitle());
                vo.setSqlCheckName(BaseConstants.getConstantsCodeMap().get(String.valueOf(vo.getSqlCheck())));
                vo.setEnvCheckName(BaseConstants.getConstantsCodeMap().get(String.valueOf(vo.getEnvCheck())));
                vo.setDeployStatusName(BaseConstants.getConstantsCodeMap().get(String.valueOf(vo.getDeployStatus())));
            }
        }
        ipage.setResult(result);
        return ipage;
    }

    @Override
    public List<WindowPlansVo> pageList(WindowPlansRequest request) {
        Page<WindowPlans> page = PageHelper.startPage(request.getPageNum(), request.getPageSize());
        Example example = new Example(WindowPlans.class);
        example.setOrderByClause("CREATE_TIME DESC");
        windowPlansMapper.selectByExample(example);
        List<WindowPlans> result = GsonUtils.getInstance().fromJson(GsonUtils.getInstance().toJson(page), new TypeToken<List<WindowPlans>>() {
        }.getType());
        List<WindowPlansVo> wvos = new ArrayList<>();
        for (WindowPlans windowPlan : result) {
            WindowPlansFiles windowPlansFiles = new WindowPlansFiles();
            windowPlansFiles.setWindowPlansId(windowPlan.getId());
            List<WindowPlansFiles> files = windowPlansFilesMapper.select(windowPlansFiles);
            List<WindowPlansFilesVo> filesVos = GsonUtils.getInstance().fromJson(GsonUtils.getInstance().toJson(files), new TypeToken<List<WindowPlansFilesVo>>() {
            }.getType());
            WindowPlansVo vo = GsonUtils.getInstance().fromJson(GsonUtils.getInstance().toJson(windowPlan), WindowPlansVo.class);
            vo.setFileList(filesVos);
            wvos.add(vo);
        }
        return wvos;
    }

    @Override
    public int delFile(long fileId) {
        WindowPlansFiles file = new WindowPlansFiles();
        file.setId(fileId);
        return windowPlansFilesMapper.delete(file);
    }

    @Override
    public Integer save(WindowPlansVo vo, boolean isAuto) {
        Assert.isTrue(NullUtil.isNotEmpty(vo.getFileList()) && !vo.getFileList().isEmpty(),
                "上线文件不能为空");
        Assert.isTrue(ConvertUtil.rangeInDefined(vo.getSqlCheck(),
                ConvertUtil.minByParentCode(this.sqlCheckParentCode),
                ConvertUtil.maxByParentCode(this.sqlCheckParentCode)),
                "未发现SQL审核业务编号:" + vo.getSqlCheck());
        Assert.isTrue(ConvertUtil.rangeInDefined(vo.getEnvCheck(),
                ConvertUtil.minByParentCode(this.envCheckParentCode),
                ConvertUtil.maxByParentCode(this.envCheckParentCode)),
                "未发现环境审核业务编号:" + vo.getEnvCheck());
        Assert.isTrue(NullUtil.isNotEmpty(vo.getReportCode()),
                "测试报告不能为空");

        WindowInfo windowInfo = new WindowInfo();
        windowInfo.setWindowDate(vo.getWindowDate());
        windowInfo = windowInfoMapper.selectOne(windowInfo);
        Assert.isTrue(NullUtil.isNotEmpty(windowInfo), "未查询到窗口信息");
        long plansId = idGenerator.nextId();
        //如果为手动新增，则需要拼接附件关联数据
        if (!isAuto) {
            ApproveDocument approveDocument = new ApproveDocument();
            approveDocument.setAppId(Long.parseLong(vo.getReportCode()));
            approveDocument.setApproveStatus(APPROVE_STATUS_SUCCESS_CODE);
            approveDocument = approveDocumentMapper.selectOne(approveDocument);
            if (NullUtil.isNotEmpty(approveDocument)) {
                insertWindowsPlanFile(approveDocument, plansId, vo.getWindowDate());
            }
        }
        //更新文件关系
        if (NullUtil.isNotEmpty(vo.getFileList())) {
            for (WindowPlansFilesVo windowPlansFilesVo : vo.getFileList()) {
                WindowPlansFiles windowPlansFiles = new WindowPlansFiles();
                windowPlansFiles.setId(windowPlansFilesVo.getFileId());
                windowPlansFiles.setWindowPlansId(plansId);
                windowPlansFiles.setWindowDate(vo.getWindowDate());
                windowPlansFilesMapper.updateByPrimaryKeySelective(windowPlansFiles);
            }
        }

        ReportInfoTag reportInfoTag = new ReportInfoTag();
        reportInfoTag.setReportCode(vo.getReportCode());
        List<ReportInfoTag> tags = reportInfoService.getReportInfoTagList(reportInfoTag);
        //添加计划应用tag
        if (NullUtil.isNotEmpty(tags)) {
            for (ReportInfoTag rtag : tags) {
                WindowPlansTag tag = new WindowPlansTag();
                tag.setId(idGenerator.nextId());
                tag.setWindowPlansId(plansId);
                tag.setReportCode(vo.getReportCode());
                tag.setReportTagId(rtag.getId());
                tag.setDeployStatus(BaseConstantCode.DEPLOY_STATUS_NOBUILD);
                tag.setLimitStatus(LimitStatusEnum.NOT_LIMIT_STATUS.getCode());
                tag.setCreateBy("123");
                tag.setCreateTime(new Date());
                windowPlansTagMapper.insertSelective(tag);
            }
        }

        WindowPlans windowPlans = new WindowPlans();
        BeanUtils.copyProperties(vo, windowPlans);
        windowPlans.setId(plansId);
        windowPlans.setDeployStatus(BaseConstantCode.DEPLOY_STATUS_WAITING);
        windowPlans.setCreateBy("123");
        windowPlans.setCreateTime(new Date());

        //更新测试报告状态为已占用
        ReportInfo info = new ReportInfo();
        info.setReportCode(vo.getReportCode());
        info.setReportStatus(BaseConstantCode.REPORT_STATUS_OCCUPY);
        reportInfoMapper.updateReportStatus(info);
        return windowPlansMapper.insertSelective(windowPlans);
    }

    /**
     * 新增窗口附件信息
     *
     * @param approveDocument
     */
    public void insertWindowsPlanFile(ApproveDocument approveDocument, Long plansId, int windowDate) {
        Long approveId = approveDocument.getId();
        ApproveAttachment approveAttachment = new ApproveAttachment();
        approveAttachment.setApproveId(approveId);
        List<ApproveAttachment> approveAttachments = approveAttachmentMapper.select(approveAttachment);
        for (ApproveAttachment attachment : approveAttachments) {
            if ("deployNote,onlineNote,approveDecument".contains(attachment.getAttachmentType())) {
                WindowPlansFiles windowPlansFiles = new WindowPlansFiles();
                windowPlansFiles.setId(idGenerator.nextId());
                windowPlansFiles.setFileUrl(attachment.getAttachmentPath());
                windowPlansFiles.setFileName(attachment.getAttachmentName());
                windowPlansFiles.setFileType(attachment.getAttachmentSuffix());
                windowPlansFiles.setWindowPlansId(plansId);
                windowPlansFiles.setWindowDate(windowDate);
                windowPlansFiles.setCreateBy(attachment.getCreateBy());
                windowPlansFiles.setCreateTime(attachment.getCreateTime());
                windowPlansFilesMapper.insertSelective(windowPlansFiles);
            }
        }

    }

    @Override
    public List<WindowPlans> findAll() {
        return windowPlansMapper.selectAll();
    }

    @Override
    public WindowPlans getOne(WindowPlans entity) {
        if (NullUtil.isNotEmpty(entity.getId())) {
            return windowPlansMapper.selectOne(entity);
        }
        return null;
    }

    @Override
    public WindowPlansFilesVo upload(MultipartFile file) throws IOException {
        String originalFilename = file.getOriginalFilename();
        long fileId = idGenerator.nextId();
        String fileSuffix = originalFilename.substring(originalFilename.indexOf('.') + 1, originalFilename.length());
        String fileRealPath = filePathInfo.getPath() + uploadDir + String.valueOf(fileId) + "." + fileSuffix;
        File destFile = new File(fileRealPath);
        FileUtils.copyInputStreamToFile(file.getInputStream(), destFile);
        WindowPlansFiles windowPlansFiles = new WindowPlansFiles();
        windowPlansFiles.setId(fileId);
        windowPlansFiles.setFileUrl(fileRealPath);
        windowPlansFiles.setFileName(originalFilename);
        windowPlansFiles.setFileType(fileSuffix);
        windowPlansFiles.setCreateBy("123");
        windowPlansFiles.setCreateTime(new Date());
        windowPlansFilesMapper.insertSelective(windowPlansFiles);
        return new WindowPlansFilesVo(windowPlansFiles.getId(), windowPlansFiles.getFileName());
    }

    @Override
    public void downloadFile(long fileId, HttpServletResponse response) {
        WindowPlansFiles windowPlansFiles = new WindowPlansFiles();
        windowPlansFiles.setId(fileId);
        windowPlansFiles = windowPlansFilesMapper.selectOne(windowPlansFiles);
        File file = new File(windowPlansFiles.getFileUrl());
        convertUtil.outputResponse(windowPlansFiles.getFileName(), file, Integer.parseInt(String.valueOf(file.length())), response);
    }

    @Override
    public List<WindowPlansTagVo> deployAction(DeployActionRequest request) {

        Assert.isTrue(updateDeployStatusByReportCode(request.getReportCode(),
                BaseConstantCode.DEPLOY_STATUS_WAITING,
                BaseConstantCode.DEPLOY_STATUS_DEPLOYED) == 1, "应用不处于[待发布]状态");

        // 将windowPlanTag全部修改为禁止单独发布
        WindowPlansTag wpt = new WindowPlansTag();
        wpt.setLimitStatus(LimitStatusEnum.LIMIT_STATUS.getCode());
        wpt.setUpdateBy("123");
        wpt.setUpdateTime(new Date());
        wpt.setDeployStatus(BaseConstantCode.DEPLOY_STATUS_WAITING);
        Example example = new Example(WindowPlansTag.class);
        example.createCriteria().andEqualTo(REPORTCODE, request.getReportCode());
        windowPlansTagMapper.updateByExampleSelective(wpt, example);

        logger.info("==== starting boot app ===={}", request.getReportCode());
        // 调用Jenkins守护线程
        jenkinsService.watchJenkins(request.getReportCode());
        // 调用Jenkins执行job，只需执行第一个WindowPlansTags，其余在回调时一次执行
        jenkinsService.invokeJenkins(request.getReportCode());

        ReportInfoTag rep = new ReportInfoTag();
        rep.setReportCode(request.getReportCode());
        List<ReportInfoTag> tags = reportInfoService.getReportInfoTagList(rep);

        return getWindowPlansTags(tags);
    }

    @Override
    public int deployActionEx(DeployActionRequest request,String action) {
        Assert.isTrue(NullUtil.isNotEmpty(request.getReportCode())
                , "The request param is null !");
        ReportInfoTag rep = new ReportInfoTag();
        int k = 0;
        rep.setReportCode(request.getReportCode());
        List<ReportInfoTag> tags = reportInfoService.getReportInfoTagList(rep);
        List<WindowPlansTagVo> vos = getWindowPlansTags(tags);
        for (int i = 0; i < vos.size(); i++) {
            remoteService.invokeJenkins(vos.get(i), action);
            k++;
        }
        return k;

    }

    @Override
    public List<WindowPlansTagVo> deployActionOne(DeployActionRequest request) {

        // 将当前windowPlan修改为不能一键发布
        updateDeployStatusByReportCode(request.getReportCode(),
                BaseConstantCode.DEPLOY_STATUS_WAITING,
                BaseConstantCode.DEPLOY_STATUS_DEPLOYED);

        // 判断该TAG是否已经发布
        WindowPlansTag wpt = new WindowPlansTag();
        wpt.setReportTagId(request.getReportTagId());
        WindowPlansTag wptQuery = windowPlansTagMapper.selectOne(wpt);
        Assert.isTrue((wptQuery != null), "发布应用信息有误...");
        wpt = wptQuery;
        Assert.isTrue((wpt.getLimitStatus() != LimitStatusEnum.LIMIT_STATUS.getCode()),
                "应用处于[" + LimitStatusEnum.LIMIT_STATUS.getName() + "]状态，请重置后再点击发布");
        logger.info("==== starting boot app ===={}", request.getReportCode());

        // 更新单个TAG limitStatus状态
        wpt.setLimitStatus(LimitStatusEnum.LIMIT_STATUS.getCode());
        wpt.setUpdateBy("123");
        wpt.setUpdateTime(new Date());
        wpt.setDeployStatus(BaseConstantCode.DEPLOY_STATUS_WAITING);
        windowPlansTagMapper.updateByPrimaryKeySelective(wpt);

        // 调用Jenkins守护线程
        jenkinsService.watchJenkins(request.getReportCode());
        // 调用Jenkins执行job
        jenkinsService.invokeJenkins(request.getReportCode());

        // 查询显示信息
        ReportInfoTag rep = new ReportInfoTag();
        rep.setReportCode(request.getReportCode());
        List<ReportInfoTag> tags = reportInfoService.getReportInfoTagList(rep);

        return getWindowPlansTags(tags);
    }

    @Override
    public int updateDeployStatusByReportCode(String reportCode, Integer deployStatusOne, Integer deployStatusTwo) {
        return windowPlansMapper.updateDeployStatusByReportCode(reportCode,
                deployStatusOne, deployStatusTwo,
                "123", new Date());
    }

    @Override
    public List<WindowPlansTagVo> getWindowPlansTags(List<ReportInfoTag> tags) {
        List<WindowPlansTagVo> vos = new ArrayList<>();
        for (ReportInfoTag infotag : tags) {
            WindowPlansTagVo vo = new WindowPlansTagVo();
            BeanUtils.copyProperties(infotag, vo);
            vo.setReportTagId(infotag.getId());
            WindowPlansTag pt = new WindowPlansTag();
            pt.setReportTagId(infotag.getId());
            pt = windowPlansTagMapper.selectOne(pt);
            if (NullUtil.isNotEmpty(pt)) {
                vo.setId(pt.getId());
                vo.setWindowPlansId(pt.getWindowPlansId());
                vo.setDeployStatus(pt.getDeployStatus());
                vo.setProgress(DeployPercentEnum.value(pt.getDeployStatus()));
                vo.setProgressColor(ProgressColorEnum.value(pt.getDeployStatus()));
                vo.setDeployStatusName(BaseConstants.getConstantsCodeMap().get(String.valueOf(pt.getDeployStatus())));
            } else {
                vo.setProgress(DeployPercentEnum.value(null));
                vo.setProgressColor(ProgressColorEnum.value(null));
            }
            vos.add(vo);
        }
        return vos;
    }

    @Override
    public List<WindowPlansTagVo> cleanQueue(DeployActionRequest request) {
        // 更新发布页面信息
        Example example = new Example(WindowPlansTag.class);
        example.createCriteria().andEqualTo(REPORTCODE, request.getReportCode());

        WindowPlansTag windowPlansTag = new WindowPlansTag();
        windowPlansTag.setLimitStatus(LimitStatusEnum.NOT_LIMIT_STATUS.getCode());
        windowPlansTagMapper.updateByExampleSelective(windowPlansTag, example);

        example.clear();
        example.createCriteria().andEqualTo(REPORTCODE, request.getReportCode()).andEqualTo("deployStatus", BaseConstantCode.DEPLOY_STATUS_WAITING);
        windowPlansTag.setDeployStatus(BaseConstantCode.DEPLOY_STATUS_RESET);
        windowPlansTagMapper.updateByExampleSelective(windowPlansTag, example);

        windowPlansMapper.updateDeployStatusByReportCode(request.getReportCode(),
                BaseConstantCode.DEPLOY_STATUS_DEPLOYED, BaseConstantCode.DEPLOY_STATUS_WAITING,
                "123", new Date());

        ReportInfoTag rep = new ReportInfoTag();
        rep.setReportCode(request.getReportCode());
        List<ReportInfoTag> tags = reportInfoService.getReportInfoTagList(rep);

        return getWindowPlansTags(tags);
    }

    /**
     * 手动翻转项目为完成状态
     *
     * @param request
     * @return
     */
    @Override
    public List<WindowPlansTagVo> deployDoneOne(DeployActionRequest request) {
        Example example = new Example(WindowPlansTag.class);
        example.createCriteria().andEqualTo("reportTagId", request.getReportTagId());
        // 更新单个TAG信息
        WindowPlansTag wpt = new WindowPlansTag();
        wpt.setUpdateBy("123");
        wpt.setUpdateTime(new Date());
        wpt.setDeployStatus(BaseConstantCode.JENKINS_STATUS_CHECK_OK);
        windowPlansTagMapper.updateByExampleSelective(wpt, example);

        // 更新jira系统状态
        int jiraResult = jiraService.changeVersionStatus(request.getReportCode());
        if (jiraResult == BaseConstantCode.SCHEDULED_EXEC_SUCCESS) {
            // 更新本地数据库jira
            Example exampleReportJira = new Example(ReportJira.class);
            exampleReportJira.createCriteria().andEqualTo("reportCode", request.getReportCode());
            ReportJira reportJira = new ReportJira();
            reportJira.setIssuesStatus(BaseConstants.getConstantsCodeMap().get("jiraStatus.done"));
            reportJira.setUpdateBy("Jenkins");
            reportJira.setUpdateTime(new Date());
            reportJiraMapper.updateByExampleSelective(reportJira, exampleReportJira);
        }

        // 查询显示信息
        ReportInfoTag rep = new ReportInfoTag();
        rep.setReportCode(request.getReportCode());
        List<ReportInfoTag> tags = reportInfoService.getReportInfoTagList(rep);

        return getWindowPlansTags(tags);
    }

}
